package com.assess.algorithm;

import java.util.List;
import java.util.Objects;

/**
 * 通用评分工具：
 * - 支持任意维度的权重与得分（用于指标树任意节点的局部评分）。
 * - 既可直接传权重，也可用成对比较矩阵通过 AHP 求权重后再评分。
 */
public final class MedicalEvaluationScorer {

    private MedicalEvaluationScorer() {}

    /**
     * 使用给定的各指标得分与权重计算最终得分（长度必须一致；权重将被隐式归一化）。
     */
    public static double score(double[] criterionScores, double[] weights) {
        Objects.requireNonNull(criterionScores, "criterionScores");
        Objects.requireNonNull(weights, "weights");
        if (criterionScores.length == 0 || criterionScores.length != weights.length) {
            throw new IllegalArgumentException("scores 与 weights 的长度需一致且大于 0");
        }
        double weightSum = 0.0;
        double weightedSum = 0.0;
        for (int i = 0; i < criterionScores.length; i++) {
            if (weights[i] < 0) throw new IllegalArgumentException("权重必须为非负数");
            weightSum += weights[i];
            weightedSum += criterionScores[i] * weights[i];
        }
        if (weightSum == 0.0) throw new IllegalArgumentException("权重之和必须大于 0");
        return weightedSum / weightSum;
    }

    /**
     * 通过 AHP 的成对比较矩阵求权重，并计算最终得分。
     * 返回结果包含：最终分数、权重、CR，便于检查一致性。
     */
    public static ScoreResult scoreWithAHP(double[] criterionScores, double[][] pairwiseMatrix) {
        Objects.requireNonNull(criterionScores, "criterionScores");
        Objects.requireNonNull(pairwiseMatrix, "pairwiseMatrix");
        if (criterionScores.length == 0) throw new IllegalArgumentException("scores 长度必须大于 0");
        MedicalAHP.Result r = MedicalAHP.compute(pairwiseMatrix);
        double finalScore = score(criterionScores, r.getWeights());
        return new ScoreResult(finalScore, r.getWeights(), r.getCr());
    }

    /**
     * 指标树节点数据结构（简化版）。
     * 如果是叶子节点，score 表示该指标的原始分；
     * 如果是父节点，weights/pairwiseMatrix 用于对子节点聚合。
     */
    public static class IndicatorNode {
        public String name;
        public double score; // 叶子有效
        public List<IndicatorNode> children; // 非叶子有效
        public double[] weights; // 与 children 对应
        public double[][] pairwiseMatrix; // 或者使用 AHP 矩阵求权重
    }

    /**
     * 递归计算指标树得分。
     * 优先使用 weights；若为空且提供了 pairwiseMatrix，则先用 AHP 求权重再聚合。
     */
    public static double scoreIndicatorTree(IndicatorNode node) {
        Objects.requireNonNull(node, "node");
        if (node.children == null || node.children.isEmpty()) {
            return node.score;
        }
        double[] childScores = new double[node.children.size()];
        for (int i = 0; i < node.children.size(); i++) {
            childScores[i] = scoreIndicatorTree(node.children.get(i));
        }
        double[] w;
        if (node.weights != null) {
            if (node.weights.length != childScores.length) {
                throw new IllegalArgumentException("weights 长度与子节点数不一致");
            }
            w = node.weights;
        } else if (node.pairwiseMatrix != null) {
            w = MedicalAHP.compute(node.pairwiseMatrix).getWeights();
        } else {
            throw new IllegalArgumentException("缺少权重：请提供 weights 或 pairwiseMatrix");
        }
        return score(childScores, w);
    }

    /** 最终评分结果 DTO。 */
    public static final class ScoreResult {
        private final double score;
        private final double[] weights;
        private final double cr;

        public ScoreResult(double score, double[] weights, double cr) {
            this.score = score; this.weights = weights; this.cr = cr;
        }
        public double getScore() { return score; }
        public double[] getWeights() { return weights; }
        public double getCr() { return cr; }
    }
}


